package com.peycard.service;

import java.io.IOException;
import java.math.BigDecimal;
import java.net.Socket;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.peycard.util.Constantes;
import com.peycard.util.Utils;
import com.solab.iso8583.IsoMessage;
import com.solab.iso8583.IsoType;
import com.solab.iso8583.IsoValue;
import com.solab.iso8583.MessageFactory;
import com.solab.iso8583.impl.SimpleTraceGenerator;
import com.solab.iso8583.parse.ConfigParser;

public abstract class BaseTransaction {

	public BaseTransaction() throws IOException {
		mfact = ConfigParser
				.createFromClasspathConfig("com/peycard/iso/config.xml");
	}

	private static Logger LOGGER = LoggerFactory
			.getLogger(BaseTransaction.class);
	private MessageFactory mfact;
	private Socket socket;

	private String ip = "172.18.100.61";// "192.168.1.64";
	private String port = "8011";

	private String field2;
	private String field3_n6_idop;
	private String field4_amount;
	private Date field7_date10_fhtx;
	private String field11_n6_audit;
	private Date field12_time_htx;
	private Date field13_date4_ftx;
	private String field22_n3_inputmode;
	private String field41_an16_idterminal;
	private String field49_an3_moneycode;
	private String field100_llvar_id_op_x;
	private String field124_n1_token_present;
	private String field125_lllvar_token;
	private String field126_lllvar_metadata;
	private String field127_lllvar_data;

	private String field3_resp_n6_idop;
	private String field4_resp_amount;
	private Date field7_resp_date10_fhtx;
	private String field11_resp_n6_audit;
	private Date field12_resp_time_htx;
	private Date field13_resp_date4_ftx;
	private String field22_resp_n3_inputmode;
	private String field38_resp_n6_cod_aut;
	private String field_39_resp_n2_cod_resp;
	private String field41_resp_an16_idterminal;
	private String field49_resp_an3_moneycode;
	private String field100_resp_llvar_id_op_x;
	private String field123_resp_n1_first_access;
	private Integer field124_resp_n1_token_present;
	private String field125_resp_lllvar_token;
	private String field126_resp_lllvar_metadata;
	private String field127_resp_lllvar_data;

	public void sendMessage() throws IOException, ParseException {
		IsoMessage m = buildMessage();
		/* Creacion del socket */
		Socket sock = new Socket(ip, Integer.parseInt(port));
		/* Escritura hacia el server */
		m.write(sock.getOutputStream(), 2);
		byte[] lenbuf = new byte[2];

		sock.getInputStream().read(lenbuf);
		int size = ((lenbuf[0] & 0xff) << 8) | (lenbuf[1] & 0xff);
		byte[] buf = new byte[size];
		// We're not expecting ETX in this case
		if (sock.getInputStream().read(buf) == size) {
			// We'll use this header length as a reference.
			// In practice, ISO headers for any message type are the
			// same length.
			String respHeader = mfact.getIsoHeader(0x210);
			IsoMessage resp = mfact.parseMessage(buf, respHeader == null ? 12
					: respHeader.length());
			// IsoMessage received
			buildResponse(resp);
		}

	}

	private void buildResponse(IsoMessage m) {
		if (m.hasField(3)) {
			IsoValue v3 = m.getAt(3);
			field38_resp_n6_cod_aut = (String) v3.getValue();
		}
		if (m.hasField(4)) {
			IsoValue v4 = m.getAt(4);
			field4_resp_amount = v4.getValue().toString();
		}
		if (m.hasField(7)) {
			IsoValue v7 = m.getAt(7);
			field7_resp_date10_fhtx = (Date) v7.getValue();
		}
		if (m.hasField(11)) {
			IsoValue v11 = m.getAt(11);
			field11_resp_n6_audit = (String) v11.getValue();
		}
		if (m.hasField(12)) {
			IsoValue v12 = m.getAt(12);
			field12_resp_time_htx = (Date) v12.getValue();
		}
		if (m.hasField(13)) {
			IsoValue v13 = m.getAt(13);
			field13_resp_date4_ftx = (Date) v13.getValue();
		}
		if (m.hasField(22)) {
			IsoValue v22 = m.getAt(22);
			field22_resp_n3_inputmode = (String) v22.getValue();
		}
		if (m.hasField(38)) {
			IsoValue v38 = m.getAt(38);
			field38_resp_n6_cod_aut = (String) v38.getValue();
		}
		if (m.hasField(39)) {
			IsoValue v39 = m.getAt(39);
			field_39_resp_n2_cod_resp = (String) v39.getValue();
		}
		if (m.hasField(41)) {
			IsoValue v41 = m.getAt(41);
			field41_resp_an16_idterminal = (String) v41.getValue();
		}
		if (m.hasField(49)) {
			IsoValue v49 = m.getAt(49);
			field49_resp_an3_moneycode = (String) v49.getValue();
		}
		if (m.hasField(123)) {
			IsoValue v123 = m.getAt(123);
			field123_resp_n1_first_access = (String) v123.getValue();
		}
		if (m.hasField(124)) {
			IsoValue v124 = m.getAt(124);
			field124_resp_n1_token_present = Integer.parseInt((String) v124
					.getValue());
		}
		if (m.hasField(125)) {
			IsoValue v125 = m.getAt(125);
			field125_resp_lllvar_token = (String) v125.getValue();
		}
		if (m.hasField(126)) {
			IsoValue v126 = m.getAt(126);
			field126_resp_lllvar_metadata = (String) v126.getValue();
		}
		if (m.hasField(127)) {
			IsoValue v127 = m.getAt(127);
			field127_resp_lllvar_data = (String) v127.getValue();
		}
	}

	private IsoMessage buildMessage() {
		initValues();
		mfact.setAssignDate(true);
		mfact.setUseBinaryBitmap(false);
		if (field11_n6_audit == null) {
			field11_n6_audit = String
					.valueOf(System.currentTimeMillis() % 10000);
			mfact.setTraceNumberGenerator(new SimpleTraceGenerator(Integer
					.valueOf(field11_n6_audit)));
		}
		IsoMessage m = mfact.newMessage(0x200);
		m.setBinary(false);
		m.setValue(3, field3_n6_idop, IsoType.NUMERIC, 6);
		m.setValue(4, new BigDecimal(field4_amount), IsoType.AMOUNT, 0);
		m.setValue(7, field7_date10_fhtx, IsoType.DATE10, 0);
		m.setValue(11, field11_n6_audit, IsoType.NUMERIC, 6);
		m.setValue(12, field12_time_htx, IsoType.TIME, 0);
		m.setValue(13, field13_date4_ftx, IsoType.DATE4, 0);
		m.setValue(22, field22_n3_inputmode, IsoType.NUMERIC, 3);
		m.setValue(41, field41_an16_idterminal, IsoType.ALPHA, 16);
		m.setValue(49, field49_an3_moneycode, IsoType.ALPHA, 3);
		m.setValue(100, field100_llvar_id_op_x, IsoType.LLVAR, 0);
		m.setValue(124, field124_n1_token_present, IsoType.NUMERIC, 1);
		if (field125_lllvar_token != null) {
			m.setValue(125, field125_lllvar_token, IsoType.LLLVAR, 0);
		}
		if (field126_lllvar_metadata != null) {
			m.setValue(126, field126_lllvar_metadata, IsoType.LLLVAR, 0);
		}
		if (field126_lllvar_metadata != null) {
			m.setValue(127, field127_lllvar_data, IsoType.LLLVAR, 100);
		}
		LOGGER.info(m.debugString());
		return m;
	}

	/**
	 * Inicializa los campos que tienen valor fijo en el mensaje ISO.
	 * 
	 * @throws IOException
	 * @throws ParseException
	 */
	private void initValues() {
		try {
			field4_amount = Constantes.ISO004_AMOUNT;
			field7_date10_fhtx = new Date();
			field12_time_htx = new Date();
			field13_date4_ftx = new Date();
			field22_n3_inputmode = Constantes.ISO022_VALUE;
			field41_an16_idterminal = Utils.terminalID();
			field49_an3_moneycode = Constantes.ISO049_CURRENCY_CODE;
		} catch (UnknownHostException e) {
			new Exception("No fue posible obtener la Dirección IP");
		}

	}

	/**
	 * @return the mfact
	 */
	public MessageFactory getMfact() {
		return mfact;
	}

	/**
	 * @param mfact
	 *            the mfact to set
	 */
	public void setMfact(MessageFactory mfact) {
		this.mfact = mfact;
	}

	/**
	 * @return the socket
	 */
	public Socket getSocket() {
		return socket;
	}

	/**
	 * @param socket
	 *            the socket to set
	 */
	public void setSocket(Socket socket) {
		this.socket = socket;
	}

	/**
	 * @return the ip
	 */
	public String getIp() {
		return ip;
	}

	/**
	 * @param ip
	 *            the ip to set
	 */
	public void setIp(String ip) {
		this.ip = ip;
	}

	/**
	 * @return the port
	 */
	public String getPort() {
		return port;
	}

	/**
	 * @param port
	 *            the port to set
	 */
	public void setPort(String port) {
		this.port = port;
	}

	/**
	 * @return the field2
	 */
	public String getField2() {
		return field2;
	}

	/**
	 * @param field2
	 *            the field2 to set
	 */
	public void setField2(String field2) {
		this.field2 = field2;
	}

	/**
	 * @return the field3_n6_idop
	 */
	public String getField3_n6_idop() {
		return field3_n6_idop;
	}

	/**
	 * @param field3_n6_idop
	 *            the field3_n6_idop to set
	 */
	public void setField3_n6_idop(String field3_n6_idop) {
		this.field3_n6_idop = field3_n6_idop;
	}

	/**
	 * @return the field4_amount
	 */
	public String getField4_amount() {
		return field4_amount;
	}

	/**
	 * @param field4_amount
	 *            the field4_amount to set
	 */
	public void setField4_amount(String field4_amount) {
		this.field4_amount = field4_amount;
	}

	/**
	 * @return the field7_date10_fhtx
	 */
	public Date getField7_date10_fhtx() {
		return field7_date10_fhtx;
	}

	/**
	 * @param field7_date10_fhtx
	 *            the field7_date10_fhtx to set
	 */
	public void setField7_date10_fhtx(Date field7_date10_fhtx) {
		this.field7_date10_fhtx = field7_date10_fhtx;
	}

	/**
	 * @return the field11_n6_audit
	 */
	public String getField11_n6_audit() {
		return field11_n6_audit;
	}

	/**
	 * @param field11_n6_audit
	 *            the field11_n6_audit to set
	 */
	public void setField11_n6_audit(String field11_n6_audit) {
		this.field11_n6_audit = field11_n6_audit;
	}

	/**
	 * @return the field12_time_htx
	 */
	public Date getField12_time_htx() {
		return field12_time_htx;
	}

	/**
	 * @param field12_time_htx
	 *            the field12_time_htx to set
	 */
	public void setField12_time_htx(Date field12_time_htx) {
		this.field12_time_htx = field12_time_htx;
	}

	/**
	 * @return the field13_date4_ftx
	 */
	public Date getField13_date4_ftx() {
		return field13_date4_ftx;
	}

	/**
	 * @param field13_date4_ftx
	 *            the field13_date4_ftx to set
	 */
	public void setField13_date4_ftx(Date field13_date4_ftx) {
		this.field13_date4_ftx = field13_date4_ftx;
	}

	/**
	 * @return the field22_n3_inputmode
	 */
	public String getField22_n3_inputmode() {
		return field22_n3_inputmode;
	}

	/**
	 * @param field22_n3_inputmode
	 *            the field22_n3_inputmode to set
	 */
	public void setField22_n3_inputmode(String field22_n3_inputmode) {
		this.field22_n3_inputmode = field22_n3_inputmode;
	}

	/**
	 * @return the field41_an16_idterminal
	 */
	public String getField41_an16_idterminal() {
		return field41_an16_idterminal;
	}

	/**
	 * @param field41_an16_idterminal
	 *            the field41_an16_idterminal to set
	 */
	public void setField41_an16_idterminal(String field41_an16_idterminal) {
		this.field41_an16_idterminal = field41_an16_idterminal;
	}

	/**
	 * @return the field49_an3_moneycode
	 */
	public String getField49_an3_moneycode() {
		return field49_an3_moneycode;
	}

	/**
	 * @param field49_an3_moneycode
	 *            the field49_an3_moneycode to set
	 */
	public void setField49_an3_moneycode(String field49_an3_moneycode) {
		this.field49_an3_moneycode = field49_an3_moneycode;
	}

	/**
	 * @return the field100_llvar_id_op_x
	 */
	public String getField100_llvar_id_op_x() {
		return field100_llvar_id_op_x;
	}

	/**
	 * @param field100_llvar_id_op_x
	 *            the field100_llvar_id_op_x to set
	 */
	public void setField100_llvar_id_op_x(String field100_llvar_id_op_x) {
		this.field100_llvar_id_op_x = field100_llvar_id_op_x;
	}

	/**
	 * @return the field124_n1_token_present
	 */
	public String getField124_n1_token_present() {
		return field124_n1_token_present;
	}

	/**
	 * @param field124_n1_token_present
	 *            the field124_n1_token_present to set
	 */
	public void setField124_n1_token_present(String field124_n1_token_present) {
		this.field124_n1_token_present = field124_n1_token_present;
	}

	/**
	 * @return the field125_lllvar_token
	 */
	public String getField125_lllvar_token() {
		return field125_lllvar_token;
	}

	/**
	 * @param field125_lllvar_token
	 *            the field125_lllvar_token to set
	 */
	public void setField125_lllvar_token(String field125_lllvar_token) {
		this.field125_lllvar_token = field125_lllvar_token;
	}

	/**
	 * @return the field126_lllvar_metadata
	 */
	public String getField126_lllvar_metadata() {
		return field126_lllvar_metadata;
	}

	/**
	 * @param field126_lllvar_metadata
	 *            the field126_lllvar_metadata to set
	 */
	public void setField126_lllvar_metadata(String field126_lllvar_metadata) {
		this.field126_lllvar_metadata = field126_lllvar_metadata;
	}

	/**
	 * @return the field127_lllvar_data
	 */
	public String getField127_lllvar_data() {
		return field127_lllvar_data;
	}

	/**
	 * @param field127_lllvar_data
	 *            the field127_lllvar_data to set
	 */
	public void setField127_lllvar_data(String field127_lllvar_data) {
		this.field127_lllvar_data = field127_lllvar_data;
	}

	/**
	 * @return the field3_resp_n6_idop
	 */
	public String getField3_resp_n6_idop() {
		return field3_resp_n6_idop;
	}

	/**
	 * @param field3_resp_n6_idop
	 *            the field3_resp_n6_idop to set
	 */
	public void setField3_resp_n6_idop(String field3_resp_n6_idop) {
		this.field3_resp_n6_idop = field3_resp_n6_idop;
	}

	/**
	 * @return the field4_resp_amount
	 */
	public String getField4_resp_amount() {
		return field4_resp_amount;
	}

	/**
	 * @param field4_resp_amount
	 *            the field4_resp_amount to set
	 */
	public void setField4_resp_amount(String field4_resp_amount) {
		this.field4_resp_amount = field4_resp_amount;
	}

	/**
	 * @return the field7_resp_date10_fhtx
	 */
	public Date getField7_resp_date10_fhtx() {
		return field7_resp_date10_fhtx;
	}

	/**
	 * @param field7_resp_date10_fhtx
	 *            the field7_resp_date10_fhtx to set
	 */
	public void setField7_resp_date10_fhtx(Date field7_resp_date10_fhtx) {
		this.field7_resp_date10_fhtx = field7_resp_date10_fhtx;
	}

	/**
	 * @return the field11_resp_n6_audit
	 */
	public String getField11_resp_n6_audit() {
		return field11_resp_n6_audit;
	}

	/**
	 * @param field11_resp_n6_audit
	 *            the field11_resp_n6_audit to set
	 */
	public void setField11_resp_n6_audit(String field11_resp_n6_audit) {
		this.field11_resp_n6_audit = field11_resp_n6_audit;
	}

	/**
	 * @return the field12_resp_time_htx
	 */
	public Date getField12_resp_time_htx() {
		return field12_resp_time_htx;
	}

	/**
	 * @param field12_resp_time_htx
	 *            the field12_resp_time_htx to set
	 */
	public void setField12_resp_time_htx(Date field12_resp_time_htx) {
		this.field12_resp_time_htx = field12_resp_time_htx;
	}

	/**
	 * @return the field13_resp_date4_ftx
	 */
	public Date getField13_resp_date4_ftx() {
		return field13_resp_date4_ftx;
	}

	/**
	 * @param field13_resp_date4_ftx
	 *            the field13_resp_date4_ftx to set
	 */
	public void setField13_resp_date4_ftx(Date field13_resp_date4_ftx) {
		this.field13_resp_date4_ftx = field13_resp_date4_ftx;
	}

	/**
	 * @return the field22_resp_n3_inputmode
	 */
	public String getField22_resp_n3_inputmode() {
		return field22_resp_n3_inputmode;
	}

	/**
	 * @param field22_resp_n3_inputmode
	 *            the field22_resp_n3_inputmode to set
	 */
	public void setField22_resp_n3_inputmode(String field22_resp_n3_inputmode) {
		this.field22_resp_n3_inputmode = field22_resp_n3_inputmode;
	}

	/**
	 * @return the field38_resp_n6_cod_aut
	 */
	public String getField38_resp_n6_cod_aut() {
		return field38_resp_n6_cod_aut;
	}

	/**
	 * @param field38_resp_n6_cod_aut
	 *            the field38_resp_n6_cod_aut to set
	 */
	public void setField38_resp_n6_cod_aut(String field38_resp_n6_cod_aut) {
		this.field38_resp_n6_cod_aut = field38_resp_n6_cod_aut;
	}

	/**
	 * @return the field_39_resp_n2_cod_resp
	 */
	public String getField_39_resp_n2_cod_resp() {
		return field_39_resp_n2_cod_resp;
	}

	/**
	 * @param field_39_resp_n2_cod_resp
	 *            the field_39_resp_n2_cod_resp to set
	 */
	public void setField_39_resp_n2_cod_resp(String field_39_resp_n2_cod_resp) {
		this.field_39_resp_n2_cod_resp = field_39_resp_n2_cod_resp;
	}

	/**
	 * @return the field41_resp_an16_idterminal
	 */
	public String getField41_resp_an16_idterminal() {
		return field41_resp_an16_idterminal;
	}

	/**
	 * @param field41_resp_an16_idterminal
	 *            the field41_resp_an16_idterminal to set
	 */
	public void setField41_resp_an16_idterminal(
			String field41_resp_an16_idterminal) {
		this.field41_resp_an16_idterminal = field41_resp_an16_idterminal;
	}

	/**
	 * @return the field49_resp_an3_moneycode
	 */
	public String getField49_resp_an3_moneycode() {
		return field49_resp_an3_moneycode;
	}

	/**
	 * @param field49_resp_an3_moneycode
	 *            the field49_resp_an3_moneycode to set
	 */
	public void setField49_resp_an3_moneycode(String field49_resp_an3_moneycode) {
		this.field49_resp_an3_moneycode = field49_resp_an3_moneycode;
	}

	/**
	 * @return the field100_resp_llvar_id_op_x
	 */
	public String getField100_resp_llvar_id_op_x() {
		return field100_resp_llvar_id_op_x;
	}

	/**
	 * @param field100_resp_llvar_id_op_x
	 *            the field100_resp_llvar_id_op_x to set
	 */
	public void setField100_resp_llvar_id_op_x(
			String field100_resp_llvar_id_op_x) {
		this.field100_resp_llvar_id_op_x = field100_resp_llvar_id_op_x;
	}

	/**
	 * @return the field123_resp_n1_first_access
	 */
	public String getField123_resp_n1_first_access() {
		return field123_resp_n1_first_access;
	}

	/**
	 * @param field123_resp_n1_first_access
	 *            the field123_resp_n1_first_access to set
	 */
	public void setField123_resp_n1_first_access(
			String field123_resp_n1_first_access) {
		this.field123_resp_n1_first_access = field123_resp_n1_first_access;
	}

	/**
	 * @return the field124_resp_n1_token_present
	 */
	public Integer getField124_resp_n1_token_present() {
		return field124_resp_n1_token_present;
	}

	/**
	 * @param field124_resp_n1_token_present
	 *            the field124_resp_n1_token_present to set
	 */
	public void setField124_resp_n1_token_present(
			Integer field124_resp_n1_token_present) {
		this.field124_resp_n1_token_present = field124_resp_n1_token_present;
	}

	/**
	 * @return the field125_resp_lllvar_token
	 */
	public String getField125_resp_lllvar_token() {
		return field125_resp_lllvar_token;
	}

	/**
	 * @param field125_resp_lllvar_token
	 *            the field125_resp_lllvar_token to set
	 */
	public void setField125_resp_lllvar_token(String field125_resp_lllvar_token) {
		this.field125_resp_lllvar_token = field125_resp_lllvar_token;
	}

	/**
	 * @return the field126_resp_lllvar_metadata
	 */
	public String getField126_resp_lllvar_metadata() {
		return field126_resp_lllvar_metadata;
	}

	/**
	 * @param field126_resp_lllvar_metadata
	 *            the field126_resp_lllvar_metadata to set
	 */
	public void setField126_resp_lllvar_metadata(
			String field126_resp_lllvar_metadata) {
		this.field126_resp_lllvar_metadata = field126_resp_lllvar_metadata;
	}

	/**
	 * @return the field127_resp_lllvar_data
	 */
	public String getField127_resp_lllvar_data() {
		return field127_resp_lllvar_data;
	}

	/**
	 * @param field127_resp_lllvar_data
	 *            the field127_resp_lllvar_data to set
	 */
	public void setField127_resp_lllvar_data(String field127_resp_lllvar_data) {
		this.field127_resp_lllvar_data = field127_resp_lllvar_data;
	}

}
